﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using AteneoLibriBusinessLogic.Entities;

namespace AteneoLibriBusinessLogic.Utility
{
    public class DistanceUtility
    {

        public static int THRESHOLD = 30;
        public static double TITLE_WEIGHT = 4;
        public static double AUTHOR_WEIGHT = 1.7;
        public static string[] separator = new string[] { " ", "'" };

        public static int LevenshteinDistance(string s, string t)
        {
            if (string.IsNullOrEmpty(s))
            {
                if (!string.IsNullOrEmpty(t))
                {
                    return t.Length;
                }
                return 0;
            }

            if (string.IsNullOrEmpty(t))
            {
                if (!string.IsNullOrEmpty(s))
                {
                    return s.Length;
                }
                return 0;
            }

            Int32 cost;
            Int32[,] d = new int[s.Length + 1, t.Length + 1];
            Int32 min1;
            Int32 min2;
            Int32 min3;

            for (Int32 i = 0; i <= d.GetUpperBound(0); i += 1)
            {
                d[i, 0] = i;
            }

            for (Int32 i = 0; i <= d.GetUpperBound(1); i += 1)
            {
                d[0, i] = i;
            }

            for (Int32 i = 1; i <= d.GetUpperBound(0); i += 1)
            {
                for (Int32 j = 1; j <= d.GetUpperBound(1); j += 1)
                {
                    cost = Convert.ToInt32(!(s[i - 1] == t[j - 1]));

                    min1 = d[i - 1, j] + 1;
                    min2 = d[i, j - 1] + 1;
                    min3 = d[i - 1, j - 1] + cost;
                    d[i, j] = Math.Min(Math.Min(min1, min2), min3);
                }
            }

            return d[d.GetUpperBound(0), d.GetUpperBound(1)];
        }

        public static double GetPercentage(double rank, double perfectMatch)
        {
            double percentage = 0xd;
            if (perfectMatch > 0)
            {
                percentage = (rank / perfectMatch) * 100;
            }
            return percentage;
        }

        public static double CalculateRank(string entry, string query, bool isQuery)
        {
            string[] entryWords = entry.Split(separator, StringSplitOptions.RemoveEmptyEntries);
            string[] queryWords = query.Split(separator, StringSplitOptions.RemoveEmptyEntries);

            double rank = 0;
            double boost = 1d;

            for (int i = 0; i < entryWords.Length; i++)
            {
                KeyValuePair<int, string> match = (KeyValuePair<int, string>)GetBestMatch(entryWords[i], queryWords).First();
                int diff = match.Value.Length - match.Key;
                if (diff > 0)
                {
                    if (match.Value.Equals(entryWords[i]) && isQuery) // boost per le parole uguali - diff == entryWords[i].Length
                        boost = 8d;
                    else
                        boost = 1d;

                    rank += Math.Floor((double)(match.Value.Length - match.Key) * boost) * Math.Pow(entryWords[i].Length, 2);
                }
            }

            return rank;
        }

        public static Dictionary<int, string> GetBestMatch(string entryWord, string[] queryWords)
        {
            int bestMatch = int.MaxValue;
            string matchWord = string.Empty;
            Dictionary<int, string> dictionary = new Dictionary<int, string>();

            for (int i = 0; i < queryWords.Length; i++)
            {
                int dLev = LevenshteinDistance(queryWords[i], entryWord);
                if (dLev <= bestMatch)
                {
                    bestMatch = dLev;
                    matchWord = queryWords[i];
                }
            }

            dictionary.Add(bestMatch, matchWord);

            return dictionary;
        }

        //public static int GetPerfectMatch(string entry)
        //{
        //    string[] entryWords = entry.Split(separator, StringSplitOptions.RemoveEmptyEntries);
        //    int matchSum = 0;
        //    int n = entryWords.Length;

        //    for (int i = 0; i < entryWords.Length; i++)
        //    {
        //        matchSum += Convert.ToInt32(Math.Pow(entryWords[i].Length, n));
        //    }

        //    return matchSum;
        //}

    }
}